home *** CD-ROM | disk | FTP | other *** search
/ Internet Publisher's Toolbox 2.0 / Internet Publisher's Toolbox.iso / internet / ntserver / wtsource / irretrvl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-14  |  22.6 KB  |  770 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.  
  4.   
  5. */
  6.  
  7. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  8.  
  9. #ifndef lint
  10. static char *RCSid = "$Header: /archives/stelar/src/freeWAIS/freeWAIS-0.2/ir/RCS/irretrvl.c,v 1.3 93/07/02 18:20:58 warnock Exp $";
  11. #endif
  12.  
  13. /* Change log:
  14.  * $Log:        irretrvl.c,v $
  15.  * Revision 1.3  93/07/02  18:20:58  warnock
  16.  * drop-in replacement for getData and getDocumentText from francois
  17.  * added gopher patches again
  18.  * 
  19.  * Revision 1.2  93/06/23  19:50:38  warnock
  20.  * Added Francois' fixes for gopher in getData and getDocumentText
  21.  * 
  22.  * Revision 1.1  93/02/16  15:05:35  freewais
  23.  * Initial revision
  24.  * 
  25.  * Revision 1.30  92/05/10  14:43:59  jonathan
  26.  * 
  27.  * Made a little safer on NULL docid's when parsing.
  28.  * 
  29.  * Revision 1.29  92/05/06  17:31:26  jonathan
  30.  * modified #if's for NeXT and Mach.  Added S_ISDIR definition for them both.
  31.  * 
  32.  * Revision 1.28  92/05/04  17:19:54  jonathan
  33.  * Added test for parsing docids (if null, log error).
  34.  * 
  35.  * Revision 1.27  92/04/28  16:56:08  morris
  36.  * added boolean to serial engine
  37.  * 
  38.  * Revision 1.26  92/04/01  17:09:46  jonathan
  39.  * Added index_directory to check_for_legitimate_file to test if filename is
  40.  * under default directory (for FTP-like retrieval).
  41.  * 
  42.  * 
  43.  * Revision 1.25  92/03/18  08:54:41  jonathan
  44.  * Removed databaseName argument from getData and getDocumentText.  The
  45.  * database name is now culled from the docid.  Removed special cases for INFO
  46.  * and Quest db's, as they should no longer be needed.
  47.  * 
  48.  * Revision 1.24  92/02/18  14:04:49  jonathan
  49.  * in check_for_legitimate_file: added INFO to the list of special case
  50.  * retrievals from MAC's.
  51.  * 
  52.  * Revision 1.23  92/02/18  11:53:45  jonathan
  53.  * conditionalized use of tempnam for NeXT (doesn't exist, use tmpnam
  54.  * instead).  May be a BSD thing.
  55.  * 
  56.  * Revision 1.22  92/02/17  12:38:52  jonathan
  57.  * special case catalog in check_for_legitimate_file.
  58.  * 
  59.  * Revision 1.21  92/02/16  18:04:52  jonathan
  60.  * Demoted more WLOG_ERROR's to WLOG_WARNING's
  61.  * 
  62.  * Revision 1.20  92/02/15  19:40:30  jonathan
  63.  * Improved reporting of retrieval errors.
  64.  * 
  65.  * Revision 1.19  92/02/15  18:58:38  jonathan
  66.  * Changed most (but not all) waislog errors to warnings on retrieval.
  67.  * 
  68.  * Revision 1.18  92/02/14  16:06:20  jonathan
  69.  * Fixed text in error message for invalid docid (not in DB)
  70.  * 
  71.  * Revision 1.17  92/02/14  15:24:08  jonathan
  72.  * Made parseDocID public.
  73.  * 
  74.  * Revision 1.16  92/02/12  13:29:35  jonathan
  75.  * Added "$Log" so RCS will put the log message in the header
  76.  * 
  77. */
  78.  
  79. /* retrieval part of the serial ir engine.  if you are using a different 
  80.    storage system for the documents, replace this file.
  81.  
  82.    -brewster
  83.  
  84.  10/91 added .Z file support from mlm@cs.brown.edu (Moises Lejter)
  85.  
  86.  to do:
  87.   handle .Z files at a lower level.
  88.  
  89.  */
  90.  
  91. #include "irretrvl.h"
  92. #include "irfiles.h" /* for filename_table_ext */
  93. #include <string.h>
  94. #include "futil.h"
  95. #include <ctype.h>  /* for isspace */
  96. #include "irext.h"
  97. #include "irdirent.h"
  98. #include <sys/types.h>
  99. #include <sys/stat.h>
  100.  
  101. #ifdef Mach
  102. #include <sys/inode.h>
  103. #endif /* Mach */
  104.  
  105. #ifndef S_ISDIR
  106. #define S_ISDIR(f_mode) ((f_mode & S_IFMT) == S_IFDIR)
  107. #endif
  108.  
  109. /*----------------------------------------------------------------------*/
  110.  
  111.  
  112. boolean
  113. parseDocID(doc,filename,start_character,end_character,errorCode)
  114. DocObj* doc;
  115. char* filename;
  116. long* start_character;
  117. long* end_character;
  118. long* errorCode;
  119. {
  120.   DocID* theDocID = NULL;
  121.   char* local_id = NULL;
  122.   char* token = NULL;
  123.   long i;
  124.  
  125.   if((theDocID = docIDFromAny(doc->DocumentID)) == NULL) 
  126.     return false;
  127.  
  128.   local_id = anyToString(GetLocalID(theDocID));
  129.   
  130.   freeDocID(theDocID);
  131.  
  132.   /* parse the doc id into start pos, end pos, and filename */
  133.   /* first the start char */
  134.   token = local_id;
  135.   for (i = 0; local_id[i] != '\0' && isspace(local_id[i]) == false; i++)
  136.     ;
  137.   if (local_id[i] == '\0')
  138.    { 
  139.      waislog(WLOG_HIGH, WLOG_WARNING, 
  140.              "Attempt to retrieve data for bad doc-id: '%s'",local_id); 
  141.      *errorCode = GDT_BadDocID;
  142.      s_free(local_id);
  143.      return(false);
  144.    }
  145.   local_id[i] = '\0';
  146.   sscanf(token,"%ld",start_character);
  147.   /* now the second char */
  148.   token = local_id + i + 1;
  149.   for (++i; local_id[i] != '\0' && isspace(local_id[i]) == false; i++)
  150.    ;
  151.   if (local_id[i] == '\0')
  152.    { 
  153.      waislog(WLOG_HIGH, WLOG_WARNING, 
  154.              "Attempt to retrieve data for bad doc-id: '%s'",local_id); 
  155.      *errorCode = GDT_BadDocID;
  156.      s_free(local_id);
  157.      return(false);
  158.    }
  159.   local_id[i] = '\0';
  160.   sscanf(token,"%ld",end_character);
  161.   /* and finally the file name */
  162.   strncpy(filename,local_id + i + 1,MAX_FILENAME_LEN);
  163.   s_free(local_id);
  164.   return(true);
  165. }
  166.  
  167.  
  168. /*----------------------------------------------------------------------*/
  169.  
  170. /* this checks to make sure that the filename is a file 
  171.    within the database */
  172.  
  173. static boolean check_for_legitimate_file 
  174.   _AP((char *filename, char* database_name, char* index_directory));
  175.  
  176. static boolean check_for_legitimate_file(filename, database_name, index_directory)
  177.      char *filename;
  178.      char *database_name;  /* full pathname of the database */
  179.      char *index_directory;
  180. {
  181.   struct stat sbuf;
  182.  
  183.   /* the help file and catalog file (the .src and .cat files) must be
  184.      special cased because it is not in the filename table */
  185.  
  186.   /* caching is done in filename_in_filename_file for repeated requests 
  187.      for the same file, so it does not need to be repeated here. */
  188.  
  189.   if(NULL != strstr(filename, ".src")) /* let it pass */
  190.     return(true);
  191.  
  192.   if(NULL != strstr(filename, ".cat")) /* let it pass */
  193.     return(true);
  194.  
  195.   stat(filename, &sbuf);
  196.   if(S_ISDIR(sbuf.st_mode)) {
  197.     waislog(WLOG_HIGH, WLOG_WARNING, 
  198.             "File: '%s' is a directory, and cannot be retrieved.",
  199.             filename);
  200.     return(false);
  201.   }
  202.   else {
  203.     /* name of the file of the filetable for this db (eg  /bar/foo.fn).  confusing, no? */
  204.     char filename_table_filename[MAX_FILE_NAME_LEN +1]; 
  205.     
  206.     pathname_directory(database_name, filename_table_filename);
  207. #ifdef WIN32
  208.     /* Append a \ if there's not one already */
  209.     if (filename_table_filename[strlen(filename_table_filename)-1]!='\\')
  210.         strncat(filename_table_filename, "\\", MAX_FILE_NAME_LEN);
  211. #else
  212.     strncat(filename_table_filename, "/", MAX_FILE_NAME_LEN);
  213. #endif
  214.     strncat(filename_table_filename, 
  215.             database_file(pathname_name(database_name)), 
  216.             MAX_FILE_NAME_LEN);
  217.     s_strncat(filename_table_filename, filename_table_ext, MAX_FILE_NAME_LEN,
  218.               MAX_FILE_NAME_LEN);
  219.     if(!filename_in_filename_file(filename, NULL, NULL, filename_table_filename)){
  220.       /* we lose.  this means either the db does not exist, or
  221.          the file is not in that db.  Log the bad news */
  222.       if(index_directory == NULL)
  223.         return true;
  224.       else if (substrcmp(filename, index_directory))
  225.         return true;
  226.       waislog(WLOG_HIGH, WLOG_WARNING, 
  227.               "File: '%s' is not in DB '%s', and cannot be retrieved.",
  228.               filename, filename_table_filename);
  229.       return(false);
  230.     }
  231.     else{                       /* everything is peachy */
  232.       return(true);
  233.     }
  234.   }
  235. }
  236.   
  237.  
  238. /*--New one--------------------------------------------------------------------*/
  239.  
  240. WAISDocumentText* getData(doc, errorCode, index_directory)
  241. DocObj* doc;
  242. long* errorCode;
  243. char* index_directory;
  244. /* it isn't text, so we can just grab data */
  245. {
  246.   FILE* file = NULL;
  247.   char fileName[MAX_FILENAME_LEN + 1];
  248.   char savedFileName[MAX_FILENAME_LEN + 1];
  249.   char* dbname = NULL;
  250.   WAISDocumentText* data = NULL;
  251.   long start,end;               /* position of the document in the file */
  252.   long startByte,endByte,bytes,bytesRead; /* part of the doc that we want */
  253.   char* buffer = NULL;
  254.   any* bufAny = NULL;
  255.   DocID *docid;
  256.   char *tmpFileName = NULL;
  257.   
  258.   
  259. /* multitype extensions */
  260.   long int j = 0L;
  261.   Boolean multitypeFlag = false;
  262.   
  263.   *errorCode = GDT_NoError;
  264.  
  265.   /* we can only handle byte chunks here */
  266.   if ((doc->ChunkCode == CT_byte) ||
  267.       (doc->ChunkCode == CT_document)) {
  268.     if (parseDocID(doc,fileName,&start,&end,errorCode) == false)
  269.      {
  270.        waislog(WLOG_HIGH, WLOG_WARNING, "can't parse DocID");
  271.        *errorCode = GDT_MissingDocID;
  272.        return(NULL);
  273.      }
  274.  
  275.   
  276.     docid = docIDFromAny(doc->DocumentID);
  277.     dbname = anyToString(GetDatabase(docid));
  278.     freeDocID(docid);
  279.     
  280.     
  281.  
  282.     if(true == check_for_legitimate_file(fileName, dbname, index_directory)){
  283.  
  284.       
  285. /* multitype extensions */
  286. /* here we have the multitype extensions - we save the fileName and probe for a 
  287.    multi-type file
  288.  */
  289.          multitypeFlag = true;
  290.  
  291.          if ( strcmp(fileName+(strlen(fileName)-2), ".Z") == 0 ) {
  292.          /* it's a .Z file.  First, remove the suffix or many things get confused. */
  293.            fileName[(strlen(fileName)-2)] = 0;
  294.          }
  295.          strcpy(savedFileName,fileName);
  296.          
  297.          /* strip the current extension, but not the period */
  298.          for ( j = strlen(fileName); j >= 0L; j-- ) {
  299.             if (fileName[j] == '.') {
  300.                fileName[j+1] = 0;
  301.                break;
  302.             }
  303.          }
  304.          
  305.          /* append the passed type to the file name */
  306.          /* need to cut the document type short - gopher seems to send back 
  307.             document type information
  308.          */
  309.          if (doc->Type) {
  310. #ifdef WIN32
  311.          for ( j = 0L; j <= (long)strlen(doc->Type); j++) {
  312. #else
  313.          for ( j = 0L; j <= strlen(doc->Type); j++) {
  314. #endif
  315.            if (isupper(doc->Type[j]) == false) {
  316.              doc->Type[j] = 0;
  317.              break;
  318.             }
  319.          }
  320.          strcat(fileName,doc->Type);
  321.        }
  322.       
  323.          if (probe_file(fileName)) {
  324.             file = s_fopen(fileName, "rb");
  325.          }
  326.          else if (probe_file_possibly_compressed(fileName)) {
  327.            tmpFileName = s_fzcat(fileName);
  328.            if (tmpFileName) {
  329.              file = s_fopen(tmpFileName, "rb");
  330.            }
  331.          }
  332.  
  333.       }
  334.  
  335.  
  336. /* here we try to open the legitimate file - we restore the savedFileName */
  337.      if ( file == NULL ) {
  338.      
  339.          multitypeFlag = false;
  340.          strcpy(fileName,savedFileName);
  341.          
  342.          if (probe_file(fileName)) {
  343.             file = s_fopen(fileName, "rb");
  344.          }
  345.          else if (probe_file_possibly_compressed(fileName)) {
  346.            tmpFileName = s_fzcat(fileName);
  347.            if (tmpFileName) {
  348.              file = s_fopen(tmpFileName, "rb");
  349.            }
  350.          }
  351.  
  352.       }
  353.       
  354.     
  355.  
  356.     /* file is still not there, pretty serious */
  357.     if (file == NULL) { 
  358.       waislog(WLOG_HIGH, WLOG_WARNING, 
  359.               "Attempt to retrieve data for missing file (DocID): %s",
  360.               fileName);
  361.       *errorCode = GDT_MissingDocID;
  362.       s_free(dbname);
  363.       if ( tmpFileName ) {
  364.           unlink(tmpFileName);
  365.           s_free(tmpFileName);
  366.       }
  367.       return(NULL);
  368.     }
  369.  
  370.     if (doc->ChunkCode == CT_byte) {
  371.       startByte = doc->ChunkStart.Pos + start;
  372.       endByte = doc->ChunkEnd.Pos + start;
  373.     }
  374.     else {
  375.       startByte = start;
  376.       endByte = end;
  377.     }
  378.  
  379.     waislog(WLOG_LOW, WLOG_RETRIEVE,
  380.             "Retrieving file (DocID): %s %ld %ld, byte range: %d %d, type: %s, from database %s", 
  381.             fileName, start, end, startByte, endByte, doc->Type, dbname);
  382.  
  383. /* multitype extensions */
  384. /* only perform this check if this is *NOT* a multitype file, ie there could be 
  385.    more than one document in this file
  386. */
  387.     if ((endByte > end) && (end != 0) && (multitypeFlag == false)) { 
  388.       waislog(WLOG_HIGH, WLOG_WARNING, 
  389.               "retrieval beyond bounds of file (DocID): %s %ld %ld, byte range: %ld %ld, type: %s, from database %s",
  390.               fileName,start, end, startByte,endByte,doc->Type,dbname);
  391.       *errorCode = GDT_BadRange;
  392.       endByte = end;
  393.       
  394.       if ( startByte > end ) {
  395.         s_free(dbname);
  396.         if ( tmpFileName ) {
  397.           unlink(tmpFileName);
  398.           s_free(tmpFileName);
  399.         }
  400.         return(NULL);
  401.       }
  402.     }
  403.    
  404.  
  405.  
  406.    
  407.     /* get the bytes */
  408.     if (fseek(file,startByte,SEEK_SET) != 0)
  409.       { 
  410.         waislog(WLOG_HIGH, WLOG_WARNING, 
  411.                 "retrieval can't seek to %ld in file <%s>",startByte,
  412.                 fileName);
  413.         *errorCode = GDT_BadRange;
  414.         s_free(dbname);
  415.         if ( tmpFileName ) {
  416.           unlink(tmpFileName);
  417.           s_free(tmpFileName);
  418.         }
  419.         return(NULL);
  420.       }
  421.  
  422.     bytes = endByte - startByte; 
  423.     buffer = (char*)s_malloc(bytes);
  424.   
  425.     bytesRead = fread((void*)buffer,(size_t)sizeof(char),bytes,file);
  426.   
  427. /* multitype extensions */
  428.     if (bytesRead != bytes)
  429.       { 
  430.       waislog(WLOG_HIGH, WLOG_WARNING, 
  431.               "retrieval beyond bounds of file (DocID): %s %ld %ld, byte range: %ld %ld, type: %s, from database %s",
  432.               fileName,start, end, startByte,endByte,doc->Type,dbname);
  433.         *errorCode = GDT_BadRange;
  434.         if (bytesRead == 0) {
  435.           s_free(dbname);
  436.           if ( tmpFileName ) {
  437.             unlink(tmpFileName);
  438.             s_free(tmpFileName);
  439.           }
  440.           return(NULL);
  441.         }
  442.       }
  443.   
  444.  
  445.     bufAny = makeAny(bytesRead,buffer);
  446.   
  447.     data = makeWAISDocumentText(duplicateAny(doc->DocumentID),0L,bufAny);
  448.   
  449.     /* close the files */
  450.     s_fclose(file);
  451.     s_free(dbname);
  452.  
  453.      if ( tmpFileName ) {
  454.         unlink(tmpFileName);
  455.         s_free(tmpFileName);
  456.      }
  457.      return(data);
  458.   }
  459.   else
  460.     { 
  461.       waislog(WLOG_HIGH, WLOG_WARNING, 
  462.               "search engine can only use whole documents or byte offsets for data lookup");
  463.       *errorCode = GDT_UnsupportedChunkType;
  464.  
  465.       s_free(dbname);
  466.       if ( tmpFileName ) {
  467.          unlink(tmpFileName);
  468.          s_free(tmpFileName);
  469.        }
  470.        return(NULL);
  471.     }
  472.  
  473. }
  474.  
  475. /*----------------------------------------------------------------------*/
  476.  
  477. #define BUFSZ   (size_t)5000
  478.  
  479. WAISDocumentText* getDocumentText(doc, errorCode, index_directory)
  480. DocObj* doc;
  481. long* errorCode;
  482. char* index_directory;
  483. /* find the text for doc, get the sub part if any, finally construct and
  484.    return a WAISDocumentText.  If it can not find the document 
  485.    (or some other error) it returns NULL and sets errorCode.
  486.  */
  487. {
  488.   WAISDocumentText* text = NULL;
  489.   FILE* file = NULL;
  490.   char* dbname = NULL;
  491.   char* buffer = NULL;
  492.   any* bufAny = NULL;
  493.   char fileName[MAX_FILENAME_LEN + 1];
  494.   char savedFileName[MAX_FILENAME_LEN + 1];
  495.   long start_character;
  496.   long end_character;
  497.   register long i;
  498.   long bytes,bytesRead;
  499.   long startByte,endByte,byte,lines;
  500.   DocID* theDocID = NULL;
  501.   char *tmpFileName = NULL;
  502.  
  503. /* multitype extensions */
  504.   long int j = 0L;
  505.   Boolean multitypeFlag = false;
  506.  
  507.   
  508.   *errorCode = GDT_NoError;
  509.  
  510.   /* we can only handle line chunks for now */
  511.   if (doc->ChunkCode != CT_line)
  512.    { 
  513.      waislog(WLOG_HIGH, WLOG_WARNING, 
  514.              "search engine can only use line offsets for now.");
  515.      *errorCode = GDT_UnsupportedChunkType;
  516.      return(NULL);
  517.    }
  518.  
  519.   if (parseDocID(doc,fileName,&start_character,&end_character,errorCode) == 
  520.       false) {
  521.     waislog(WLOG_HIGH, WLOG_ERROR,"Can't parse DocID");
  522.     *errorCode = GDT_MissingDocID;
  523.     return(NULL);
  524.   }
  525.  
  526.   theDocID = docIDFromAny(doc->DocumentID);
  527.   dbname = anyToString(GetDatabase(theDocID));
  528.   freeDocID(theDocID);
  529.  
  530.   waislog(WLOG_LOW, WLOG_RETRIEVE,
  531.           "Retrieving file (DocID): %s, line range: %d %d, type: %s, from database %s", 
  532.           fileName, doc->ChunkStart.Pos, doc->ChunkEnd.Pos, doc->Type,
  533.           dbname);
  534.  
  535.  
  536.   
  537.     if(true == check_for_legitimate_file(fileName, dbname, index_directory)){
  538.       
  539. /* multitype extensions */
  540. /* here we have the multitype extensions - we save the fileName and probe for a 
  541.    multi-type file
  542.  */
  543.          multitypeFlag = true;
  544.  
  545.          if ( strcmp(fileName+(strlen(fileName)-2), ".Z") == 0 ) {
  546.          /* it's a .Z file.  First, remove the suffix or many things get confused. */
  547.            fileName[(strlen(fileName)-2)] = 0;
  548.          }
  549.          strcpy(savedFileName,fileName);
  550.          
  551.          /* strip the current extension, but not the period */
  552.          for ( j = strlen(fileName); j >= 0L; j-- ) {
  553.             if (fileName[j] == '.') {
  554.                fileName[j+1] = 0;
  555.                break;
  556.             }
  557.          }
  558.          
  559.          /* append the passed type to the file name */
  560.          /* need to cut the document type short - gopher seems to send back 
  561.             document type information
  562.          */
  563. #ifdef WIN32
  564.          for ( j = 0L; j <= (long)strlen(doc->Type); j++) {
  565. #else
  566.          for ( j = 0L; j <= strlen(doc->Type); j++) {
  567. #endif
  568.            if (isupper(doc->Type[j]) == false) {
  569.              doc->Type[j] = 0;
  570.              break;
  571.             }
  572.          }
  573.          strcat(fileName,doc->Type);
  574.  
  575.       
  576.          if (probe_file(fileName)) {
  577.             file = s_fopen(fileName, "rb");
  578.          }
  579.          else if (probe_file_possibly_compressed(fileName)) {
  580.            tmpFileName = s_fzcat(fileName);
  581.            if (tmpFileName) {
  582.              file = s_fopen(tmpFileName, "rb");
  583.            }
  584.          }
  585.       }
  586.  
  587.  
  588. /* here we try to open the legitimate file - we restore the savedFileName */
  589.      if ( file == NULL ) {
  590.       
  591.          multitypeFlag = false;
  592.          strcpy(fileName,savedFileName);
  593.                   
  594.         if (probe_file(fileName)) {
  595.             file = s_fopen(fileName, "rb");
  596.          }
  597.          else if (probe_file_possibly_compressed(fileName)) {
  598.            tmpFileName = s_fzcat(fileName);
  599.            if (tmpFileName) {
  600.              file = s_fopen(tmpFileName, "rb");
  601.            }
  602.          }
  603.       }
  604.       
  605.     
  606.   
  607.     /* file is still not there, pretty serious */
  608.     if (file == NULL) { 
  609.       waislog(WLOG_HIGH, WLOG_WARNING, 
  610.               "Attempt to retrieve data for missing file (DocID): %s",
  611.               fileName);
  612.       *errorCode = GDT_MissingDocID;
  613.       s_free(dbname);
  614.       if ( tmpFileName ) {
  615.          unlink(tmpFileName);
  616.          s_free(tmpFileName);
  617.        }
  618.       return(NULL);
  619.     }
  620.  
  621.  
  622.   if(0 != fseek(file, start_character, SEEK_SET))
  623.    { 
  624.      waislog(WLOG_HIGH, WLOG_WARNING, 
  625.              " error on attempt to seek into file for file (DocID): %s", fileName);
  626.      s_free(dbname);
  627.      *errorCode = GDT_BadRange;
  628.      if ( tmpFileName ) {
  629.         unlink(tmpFileName);
  630.         s_free(tmpFileName);
  631.       }
  632.      return(NULL);
  633.    }
  634.   /* find the start byte */
  635.   buffer = (char*)s_malloc(BUFSZ);
  636.   lines = byte = 0;
  637.   while (lines < doc->ChunkStart.Pos)
  638.    { /* search a buffer full */
  639.      bytesRead = fread(buffer,(size_t)sizeof(char),BUFSZ,file); 
  640.      for (i = 0; i < bytesRead && lines < doc->ChunkStart.Pos; i++, byte++)
  641.       { if (buffer[i] == '\n' || buffer[i] == '\r')
  642.           /* \r should not happen because we are reading the file in text 
  643.              mode */
  644.           lines++;
  645.       }
  646.      if (bytesRead == 0) /* cheasy handling files that don't end with nl */
  647.        lines++;
  648.    } 
  649.   startByte = byte;
  650.    
  651.   
  652.   /* find the end byte */ /* this could be done while getting the bytes XXX */
  653.   /* search starting form the start pos */  
  654.   if (fseek(file,startByte + start_character,SEEK_SET) != 0) 
  655.    { 
  656.      waislog(WLOG_HIGH, WLOG_WARNING, 
  657.              "retrieval can't seek to %ld in file <%s>",
  658.              startByte,fileName);
  659.      
  660.      *errorCode = GDT_BadRange;
  661.      s_free(dbname);
  662.      if ( tmpFileName ) {
  663.          unlink(tmpFileName);
  664.          s_free(tmpFileName);
  665.      }
  666.      return(NULL);
  667.    }
  668.  
  669.   
  670.   while (lines < doc->ChunkEnd.Pos) 
  671.    { /* search a buffer full */
  672.      bytesRead = fread(buffer,(size_t)sizeof(char),BUFSZ,file); 
  673.      for (i = 0; i < bytesRead && lines < doc->ChunkEnd.Pos; i++, byte++)
  674.       { if (buffer[i] == '\n' || buffer[i] == '\r')
  675.           /* \r should not happen, we are reading the file in text mode */
  676.           lines++;
  677.       }
  678.      if (bytesRead == 0) /* cheasy handling of files that don't end with nl */
  679.        lines++;
  680.    } 
  681.   endByte = byte;
  682.    
  683.   
  684. /* multitype extensions */
  685. /* only perform this check if this is *NOT* a multitype file, ie there could be 
  686.    more than one document in this file
  687. */
  688.    if ((endByte + start_character > end_character) && (end_character != 0) && (multitypeFlag == false)) { 
  689.      waislog(WLOG_HIGH, WLOG_WARNING, 
  690.               "retrieval beyond bounds of file (DocID): %s %ld %ld, byte range: %ld %ld, line range: %d %d, type: %s, from database %s",
  691.               fileName,start_character,end_character,startByte + start_character,endByte + start_character, 
  692.               doc->ChunkStart.Pos, doc->ChunkEnd.Pos, doc->Type,dbname);
  693.  
  694.       *errorCode = GDT_BadRange;
  695.       endByte = end_character - start_character;
  696.  
  697.       if ( startByte > end_character ) {
  698.         s_free(dbname);
  699.         if ( tmpFileName ) {
  700.           unlink(tmpFileName);
  701.           s_free(tmpFileName);
  702.         }
  703.         return(NULL);
  704.       }
  705.     }
  706.  
  707.   
  708.  
  709.  
  710.   s_free(buffer);
  711.      
  712.   /* get the bytes */
  713.   if (fseek(file,startByte + start_character,SEEK_SET) != 0)
  714.    { 
  715.      waislog(WLOG_HIGH, WLOG_WARNING, 
  716.              "retrieval can't seek to %ld in file <%s>",startByte,
  717.              fileName);
  718.      
  719.      *errorCode = GDT_BadRange;
  720.      s_free(dbname);
  721.      if ( tmpFileName ) {
  722.          unlink(tmpFileName);
  723.          s_free(tmpFileName);
  724.      }
  725.      return(NULL);
  726.    }
  727.    
  728.   bytes = endByte - startByte; 
  729.   buffer = (char*)s_malloc(bytes);
  730.   
  731.   bytesRead = fread((void*)buffer,(size_t)sizeof(char),bytes,file);
  732.   
  733.   if (bytesRead != bytes)
  734.   { 
  735.   
  736. /* multitype extensions */
  737. /*     waislog(WLOG_HIGH, WLOG_WARNING, 
  738.              "retrieval error in file <%s>",fileName);
  739. */
  740.      waislog(WLOG_HIGH, WLOG_WARNING, 
  741.               "retrieval beyond bounds of file (DocID): %s %ld %ld, byte range: %ld %ld, type: %s, from database %s",
  742.               fileName,start_character,end_character,startByte + start_character,endByte + start_character,
  743.               doc->ChunkStart.Pos, doc->ChunkEnd.Pos, doc->Type,dbname);
  744.      
  745.      *errorCode = GDT_BadRange;
  746.      s_free(dbname);
  747.      if ( tmpFileName ) {
  748.          unlink(tmpFileName);
  749.          s_free(tmpFileName);
  750.      }
  751.      return(NULL);
  752.    }
  753.   
  754.   bufAny = makeAny(bytesRead,buffer);
  755.   
  756.   text = makeWAISDocumentText(duplicateAny(doc->DocumentID),0L,bufAny);
  757.   
  758.   /* close the files */
  759.   s_free(dbname);
  760.   s_fclose(file);
  761.   if ( tmpFileName ) {
  762.      unlink(tmpFileName);
  763.      s_free(tmpFileName);
  764.   }
  765.  
  766.   return(text);
  767. }
  768.  
  769.  
  770.